class Vue {
  constructor(options) {
    // 1. 初始化参数
    this.$options = options || {};
    this.$data = options.data || {};
    this.$methods = options.methods || {};
    this.$el =
      typeof options.el === "string"
        ? document.querySelector(options.el)
        : options.el;
    // 调用 observer 监听 data 中所有属性的变化
    new Observer(this.$data);
    // 2. 把 data 中的属性注入到 Vue 实例, 转换成 getter/ setter
    this._proxyData(this.$data);
    // 将 method 挂载到  Vue 实例
    this.addMethodToVue(this.$methods);
    // 负责调用 compiler 解析指令/ 差值表达式
    new Compiler(this);
  }

  _proxyData(data) {
    // 遍历 $data 中的所有属性
    Object.keys(data).forEach((key) => {
      // 把 $data 属性注入到 vue 实例中, this 指向 vue 实例
      Object.defineProperty(this, key, {
        enumerable: true,
        configurable: true,
        get() {
          return data[key];
        },
        set(newValue) {
          if (newValue === data[key]) {
            return;
          }
          // 这一步不会触发 set 的操作
          data[key] = newValue;
        },
      });
    });
  }

  addMethodToVue(methods) {
    for (let [key, value] of Object.entries(methods)) {
      console.log("bind", this);
      this[key] = value.bind(this);
    }
  }
}
